#ifndef _Ring_QUEUE_HPP_
#define _Ring_QUEUE_HPP_

#include <iostream>
#include <vector>
#include<pthread.h>
#include "sem.hpp"
const int g_default_num = 5;

// 信号量本质是一把计数器->计数器又是什么呢？？可以不用进入临界区，就可以得知资源情况，甚至可以减少临界区内部的判断！
// 申请锁->判断与访问->释放锁-->本质是我们并不清楚临界资源的情况  ！！！
// 信号量要提前预设资源的情况，而且在pv变化的过程中，我们可以在外部就能知晓临界资源的情况。

// 多线程
template <class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_default_num)
    :_ring_queue(default_num),
    _num(default_num),
    c_step(0),
    p_step(0),
    _space_sem(default_num),
    _data_sem(0)
    {
        pthread_mutex_init(&clock, nullptr);
        pthread_mutex_init(&pclock, nullptr);
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&pclock);
    }

    //生产者
    void push(const T&in)
    {
        //先申请信号量(0)
        _space_sem.p();
        pthread_mutex_lock(&pclock);   //生产者需要互斥
        _ring_queue[p_step++] = in;
        p_step%=_num;
        pthread_mutex_unlock(&pclock);
        _data_sem.v();   //通知取数据
    }

    //消费者
    void pop(T *out)
    {
        _data_sem.p();
        pthread_mutex_lock(&clock);   //消费者需要互斥

        *out = _ring_queue[c_step++];
        c_step%=_num;

        pthread_mutex_unlock(&clock);
        _space_sem.v();

    }

private:
    std::vector<T> _ring_queue;
    int _num;

    int c_step;  //消费下标
    int p_step;  //生产下标   用于控制唤醒队列的队头和队尾

    Sem _space_sem;   //空间多大的信号量
    Sem _data_sem;    //数据多少的信号量

    pthread_mutex_t clock;  //消费者的锁
    pthread_mutex_t pclock;  //生产者的锁
};



#endif